#include <mongoose.h>
#include <stdint.h>
#include <Iboot_info.h>
//#include "../comm/comm_api.h"
#include <time.h>
#include <cpu_peri_gpio.h>
#include "downloader.h"

#ifndef free
#define free(x) M_Free(x)
#endif

typedef int (*FUN_NET_PROC)(unsigned char *data, int len, int total, int timeout);
typedef struct StDlFileData {
    int media_type;//0: mp3, 1: wav
    volatile int is_break;
    volatile int status;
    volatile int is_start;
    volatile unsigned int timemark;
    volatile unsigned int timeout;
    volatile unsigned int body_size;
    volatile unsigned int mark_pos;
    FUN_NET_PROC fun_net_do;
    char url[512];
}StDlFileData;

int sniprintf(char *buf, size_t buf_size, const char *fmt, ...)
{
    int result;
    va_list ap;
    va_start(ap, fmt);
    char* pnew = (char*)malloc(strlen(fmt) + 1);
    if (pnew == 0) return 0;
    strcpy(pnew, fmt);
    char *p = pnew;
    while (*p) {
        if (*p == '%' && *p != 0 && *(p + 1) == '.') {
            p++;
            *p = '0';
        }
        p++;
    }
    result = c_vsnprintf(buf, buf_size, pnew, ap);
    va_end(ap);
    if (pnew) free(pnew);
    return result;
}

int siscanf(const char *ibuf, const char *fmt, ...)
{
    va_list ap;
    int ret;
    va_start(ap, fmt);
    ret = vsscanf(ibuf, fmt, ap);
    va_end(ap);
    return(ret);
}


static void cb_http_download_handler(struct mg_connection *nc, int ev, void *ev_data)
{
    (void)ev_data;
//    struct http_message *hm = (struct http_message *) ev_data;
    struct StDlFileData *pUserData = nc->user_data;
    struct mbuf *io = &nc->recv_mbuf;
    int ret = 0;
    switch (ev) {
    case MG_EV_CONNECT:
        {
            pUserData->is_start = 1;
    #if 0
            int opt = 0;
            //        opt = 1460*2;
            //        if(0 != setsockopt(nc->sock, SOL_SOCKET ,SO_SNDBUF,&opt, 4))
            //        {
            //            printf("error: Client:set client sndbuf failed!\r\n");
            //        }

            opt = 6 * 1024;
            if (0 != setsockopt(nc->sock, SOL_SOCKET, SO_RCVBUF, &opt, 4))
            {
                printf("Client: setsockopt failed!\n\r");
            }
    #endif
            if (pUserData->is_break) {
                nc->flags |= MG_F_CLOSE_IMMEDIATELY;
            }
            pUserData->body_size = 0;
            pUserData->mark_pos = 0;
        }
        break;
    case MG_EV_RECV:
        {
            //printf("=== read: %d ===!\r\n", io->len);

            if (pUserData->is_start == 1) {
                pUserData->body_size = 0;
                pUserData->mark_pos = 0;
                pUserData->is_start = 0;
                if (0 == memcmp(io->buf, "HTTP/1.1 200", strlen("HTTP/1.1 200"))||
                    0 == memcmp(io->buf, "HTTP/1.1 206", strlen("HTTP/1.1 206"))) {

                    printf("info: http download recv header ok!\r\n");
                    char *p = 0;
                    if ((p = strstr(io->buf, "\r\n\r\n"))) {
                        p = p + 4; //p pto data
                        //memset(&shm, 0, sizeof(struct http_message));
                        //mg_http_parse_headers(io->buf, p, p-io->buf, &shm);
                        //printf("shm->body.len=%d!\r\n", shm.body.len);
                        //pUserData->body_size = shm.body.len;
                        char *plen = (char*)c_strnstr(io->buf, "Content-Length:", io->len);
                        if (!mg_ncasecmp(plen, "Content-Length:", 15)) {
                            pUserData->body_size = atoi(plen+15);
                            printf("media body size: %d!\r\n", pUserData->body_size);
                        }
                        //ret = play_data(p, io->len - (p - io->buf), 1000);
                        if (pUserData->fun_net_do) {
                            ret = pUserData->fun_net_do((unsigned char*)p, io->len - (p - io->buf), pUserData->body_size, 1000);
                        }
                        if (pUserData->body_size > 0 && io->len >= (size_t)(p - io->buf)) {
                            pUserData->mark_pos += io->len - (p - io->buf);
                        }
                        mbuf_remove(io, io->len);
                        pUserData->timemark = DJY_GetSysTime() / 1000;
                    }
                    pUserData->status = 0;
                }
                else {
                    pUserData->status = -1;
                }
            }
            else {
                //ret = play_data(io->buf, io->len, 1000);
                if (pUserData->fun_net_do) {
                    ret = pUserData->fun_net_do((unsigned char*)io->buf, io->len, pUserData->body_size, 1000);
                }
                if (io->len > 0 && ret > 0) {
                    pUserData->mark_pos += io->len;
                    mbuf_remove(io, ret);
                }
                pUserData->timemark = DJY_GetSysTime() / 1000;
            }
            //mbuf_remove(io, io->len);
            if (pUserData->is_break) {
                printf("info: is_break by man, close now!\r\n");
                nc->flags |= MG_F_CLOSE_IMMEDIATELY;
            }
            if (pUserData->body_size > 0 && pUserData->mark_pos >= pUserData->body_size) {
                printf("info: body_size full, close now!\r\n");
                nc->flags |= MG_F_CLOSE_IMMEDIATELY;
                printf("media download done: %d!\r\n", pUserData->mark_pos);
            }
        }
        break;
    case MG_EV_CLOSE:
        {
            pUserData->status = 1;
            pUserData->body_size = 0;
            pUserData->mark_pos = 0;
            //printf("===============close socket=================!\r\n");
            if (pUserData->media_type==1) {//wav
//                WavDataEndPlay (); // TODO merlin 20191214
            }
            else if (pUserData->media_type==0) { //mp3
//                Mp3DataEndPlay (); // TODO merlin 20191214
            }
        }
        break;
    }
}


int WebDownload(char *host, int port, char *path, void *fdo, int timeout_ms)
{
//    struct StAliyunOssMgr *pOssMgr = &gOssMgr;
    struct StDlFileData userData;
    struct StDlFileData *pUserData = 0;
    char GMT[60] = { 0 };
    unsigned int timestamp = 0;
    struct mg_connection *nc = 0;
    struct mg_mgr mgr;
    char *temp = 0;
    int ret = -1;
    unsigned int time_val = 0;

    printf ("WebDownload: %s!\r\n", path);

    if (!GetPingFlag()){
        pUserData->url[0] = 0;
        return -1;
    }

    temp = malloc(1024);
    if (temp == 0) goto FUN_RET;
    memset(temp, 0, 1024);

    memset(&userData, 0, sizeof(struct StDlFileData));
    pUserData = &userData;
    pUserData->fun_net_do = fdo;

    Time_Time(&timestamp);
    GTM_TIME(timestamp, GMT, sizeof(GMT));

    mg_mgr_init(&mgr, NULL);

    memset(temp, 0, 1024);
    sprintf(temp, "%s:%d", host, port);
    printf("temp is %s\r\n",temp);
    nc = mg_connect(&mgr, temp, cb_http_download_handler);
    pUserData->status = 0;
    if (nc == 0)  goto MGR_FREE;

    nc->user_data = pUserData;

    mg_set_protocol_http_websocket(nc);

    memset(temp, 0, 1024);
    sprintf(temp,
        "GET %s HTTP/1.1\r\n"
        "Host: %s\r\n"
        "User-Agent: Mongoose/6.15\r\n"
        "Accept : */*\r\n"
        "Connection: keep-alive\r\n"
        "date: %s\r\n\r\n", path, host, GMT);
    mg_printf(nc, "%s", temp);
    pUserData->timemark = DJY_GetSysTime()/1000;
    pUserData->timeout = 10000;
    while (pUserData->status == 0)
    {
        mg_mgr_poll(&mgr, 500);
        time_val = DJY_GetSysTime()/1000 - pUserData->timemark;
        if (time_val > pUserData->timeout) {
            printf("==info: WebDownloadAndPlay break!==\r\n");
            break;
        }

        pUserData->timemark = DJY_GetSysTime()/1000;

        DJY_EventDelay(10*1000);
    }

    if (time_val <= pUserData->timeout)
    {
        ret = 0;
    }

MGR_FREE:
    mg_mgr_free(&mgr);
    pUserData->url[0] = 0;

FUN_RET:
    if (temp) {
        free(temp);
        temp = 0;
    }
    return ret;
}

